from ma.commons.core.abstractreducer import AbstractReducer


class Reduce(AbstractReducer):
    """This class is normal summer reduce / or in other words a frequency
    count reduce
    """
    
    def __init__(self, key, list_of_values, key_value_dict, user_vars):     
        """
        """
        
        AbstractReducer.__init__(self, key, list_of_values, key_value_dict)
        
        # set the user variables
        self.change_margin = user_vars[0]
        self.if_changed = user_vars[1]
    
    
    def reduce(self, key, list_of_values):
        """key is the key being reduced and list of values is the 
        lists within a list that need of be reduced for that key
        if len(list_of_values) is one 
        this reduce counts frequency of key  over the list_of_values
        """
        
        max = -99999999999
        self.frequency_count = 0
        
        # iterate through list of values and add them
        for i in list_of_values:
            self.frequency_count += i
            if i > max:
                max = i
        
        value = [self.frequency_count]
        self.emit(key, value)
        
        # user calls the if changed function to see if the value has changed 
        # significantly of the key in question, if a change margin is given
        if self.change_margin != None:
            self.if_changed[0] = self.check_if_changed(max, value[0], self.change_margin)


    def check_if_changed(self, max, final_value, margin):
        """This function checks if the value has changed more than a given
        margin. This is done by seeing if the maximum value input is within
        the supplied margin from the final value
        """
        
        # if the xml provided no margin value, then the code supposes that
        # the value has always changes during the computation
        if margin == None:
            return True
        
        change = float(max) * margin 
        min_val_allowed = max - change
        max_val_allowed = max + change
        if final_value > max_val_allowed or final_value < min_val_allowed:
            return True
        else:
            return False
        